package org.finesys.common.netty.websocket.resolver;

import static org.finesys.common.netty.websocket.constants.WebSocketAttributeKeyConstants.URI_TEMPLATE;

import java.util.Collections;
import java.util.Map;

import org.finesys.common.netty.websocket.annotation.PathVariable;
import org.finesys.common.netty.websocket.support.MethodArgumentResolver;
import org.springframework.core.MethodParameter;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import io.netty.channel.Channel;

public class PathVariableMapMethodArgumentResolver implements MethodArgumentResolver {
    /**
     * 重写support方法以判断是否支持给定的方法参数。
     * <p>
     * 如果方法参数上标注了@PathVariable注解，方法参数的类型是Map或其子类，
     * 并且@PathVariable注解的value属性值为空，则返回true，表示支持该参数；
     * 否则返回false。
     *
     * @param parameter 方法参数，包含方法参数的元数据。
     * @return 如果支持给定的方法参数，则返回true；否则返回false。
     */
    @Override
    public boolean support(MethodParameter parameter) {
        PathVariable pathVariable = parameter.getParameterAnnotation(PathVariable.class);
        return (pathVariable != null && Map.class.isAssignableFrom(parameter.getParameterType())
                && !StringUtils.hasText(pathVariable.value()));
    }

    /**
     * 重写resolveArgument方法以解析方法参数。
     * <p>
     * 此方法用于从WebSocket通道接收到的请求中解析出带有@PathVariable注解的方法参数。
     *
     * @param parameter 方法参数，包含方法参数的元数据。
     * @param channel   WebSocket通道，用于处理WebSocket连接。
     * @param object    从WebSocket通道接收到的对象，本方法中未使用。
     * @return 解析后的方法参数值，返回值为Map类型，包含从URI模板变量中提取的参数名和参数值。
     * 如果URI模板变量为空，则返回一个空的Map。
     * @throws Exception 如果在解析参数过程中发生异常，则抛出该异常。
     */
    @Override
    public Object resolveArgument(MethodParameter parameter, Channel channel, Object object) throws Exception {
        PathVariable pathVariable = parameter.getParameterAnnotation(PathVariable.class);
        if(pathVariable==null){
            return Collections.EMPTY_MAP;
        }
        String name = pathVariable.value();
        if (!StringUtils.hasText(name)) {
            name = parameter.getParameterName();
            if (!StringUtils.hasText(name)) {
                throw new IllegalArgumentException(
                        "Name for argument type [" + parameter.getNestedParameterType().getName()
                                + "] not available, and parameter name information not found in class file either.");
            }
        }
        Map<String, String> uriTemplateVars = channel.attr(URI_TEMPLATE).get();
        if (!CollectionUtils.isEmpty(uriTemplateVars)) {
            return uriTemplateVars;
        }
        return Collections.EMPTY_MAP;
    }
}
